﻿#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
//动态态通讯录的实现

//通讯录
//1.可以存放100个人的信息
//2.每个人的信息：
// 名字、性别、年龄、电话、地址
//3.功能：
// 3.1 增加联系人
// 3.2 删除指定联系人
// 3.3 查找指定联系人
// 3.4 修改指定联系人
// 3.5 显示指定联系人
// 3.6 排序联系人（按照年龄/名字)

//静态版本
//初始化
//void InitContact(Contact* pc)
//{
//	pc->sz = 0;
//	//把data数组里的所有字节都初始化为0
//	memset(pc->data, 0, sizeof(pc->data));
//}

//加载原通讯录
void LoadContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("contact.dat", "rb");
	if (pf == NULL)
	{
		perror("LoadContact::fopen");
		printf("Creat a new contact now\n");
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))//利用fread的返回值设置循环条件
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

//文件动态版本
//初始化
void InitContact(Contact* pc)
{
	pc->sz = 0;
	//申请默认大小个空间
	pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		printf("通讯录已满，无法增加\n");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;

	//加载文件的信息到通讯录
	LoadContact(pc);
}



//辅助查找指定联系人，找到就返回该联系人的下标，找不到返回-1，因为下标不可能有-1（不能返回0，下标可能有0）
//这是个辅助函数，不需要被别的.c文件使用，可以加上static修饰，可以防止重名
static int FindByName(const Contact* pc, char* name)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//找到就返回下标
		if (!strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	//跳出循环就说明没找到，就返回-1
	return -1;
}

//静态版本
//添加指定联系人
//void AddContact(Contact* pc)
//{
//	//判断通讯录是否已满
//	if (pc->sz == MAX)
//	{
//		printf("通讯录已满，无法增加\n");
//		return;//直接return就行，不用返回值
//	}
//	printf("请输入名字：");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入年龄：");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入性别：");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话：");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址：");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;//有效数据量加1
//	printf("添加成功\n");
//}

//动态版本
void AddContact(Contact* pc)
{
	CheckCapacity(pc);
	printf("请输入名字：");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄：");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别：");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话：");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址：");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;//有效数据量加1
	printf("添加成功\n");
}

//删除，不能处理重名的情况
void DelContact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空，无法删除\n");
		return;
	}
	char name[MAX] = { 0 };//存放要删除的人的名字

	//1.找到要删除的人 - 位置（下标）
	printf("输入要删除人的名字：");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	//找不到查找函数就返回-1
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//2.删除 - 删除pos位置上的数据
	for (int i = pos; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;//有效数据减1
	printf("删除成功\n");
}

//查找指定联系人
void SearchContact(const Contact* pc)
{
	printf("请输入要查找联系人的名字：");
	char name[MAX_NAME] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("找不到此联系人\n");
		return;
	}
	//打印标题
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	//打印通讯录中的有效数据
	printf("%-10s %-4d %-5s %-12s %-30s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].tele,
		pc->data[pos].addr);
}

void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	printf("请输入要修改人的名字：");
	scanf("%s", name);
	//先看要修改的人存不存在
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字：");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄：");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入性别：");
	scanf("%s", pc->data[pos].sex);
	printf("请输入电话：");
	scanf("%s", pc->data[pos].tele);
	printf("请输入地址：");
	scanf("%s", pc->data[pos].addr);

	printf("修改成功\n");
}
//打印有效数据
void ShowContact(const Contact* pc)
{
	int i = 0;
	//姓名      年龄       性别      电话      地址
	//zhangsan  20         男        123456    北京

	//打印标题
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	//打印通讯录中的有效数据
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s %-4d %-5s %-12s %-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

//提供名字的比较函数
static int cmp_by_name(const void* p1, const void* p2)
{
	strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}

//按照名字来排序
void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
	printf("排序成功\n");
	ShowContact(pc);
}

//检查容量
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		if (ptr == NULL)
		{
			printf("CheckCapacity:%s\n", strerror(errno));
			return;
		}
		pc->data = ptr;
		pc->capacity += INC_SZ;
		printf("增容成功，当前容量是:%d\n", pc->capacity);
	}
}

//销毁通讯录
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("释放内存\n");
}

void SaveContact(Contact* pc)//保存通讯录
{
	//打开文件
	FILE* pf = fopen("contact.dat", "wb");
	if (pf == NULL)
	{
		perror("SaveContact::fopen");
		return;
	}
	//写数据
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	printf("保存成功\n");
}